package com.naiterui.ehp.bs.im.remote;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.naiterui.ehp.bp.bo.im.PatientMsgSendParamBO;
import com.naiterui.ehp.bp.bo.patient.MsgMaPublishParamBO;
import com.naiterui.ehp.bp.bo.patient.MsgPublishBO;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.exception.ResponseVO;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.beans.BeanUtil;
import com.naiterui.ehp.bp.utils.encypt.MD5;
import com.naiterui.ehp.bp.utils.net.RestHttpUtil;
import com.naiterui.ehp.bp.utils.thread.ThreadPoolUtil;
import com.naiterui.ehp.bs.im.config.RemoterConfig;
import com.naiterui.ehp.bs.im.feign.PatientFeginClient;
import com.naiterui.ehp.bs.im.network.protocl.DoctorsMedicalRecord;
import com.naiterui.ehp.bs.im.network.protocl.RecommandDrug;
import com.naiterui.ehp.bs.im.network.protocl.Session;
import com.naiterui.ehp.bs.im.network.protocl.SessionDetails;
import com.naiterui.ehp.bs.im.utils.Constants;
import com.naiterui.ehp.bs.im.vo.ConsultPayVO;
import com.naiterui.ehp.bs.im.vo.dto.RecomUserInfoDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class Remoter implements IRemoter {

    /**
     * LOGGER
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(Remoter.class);

    public static final String SESSION_NOTICE_SIGN_KEY = "key";
    public static final String SESSION_NOTICE_SIGN_SECRET_KEY = "aA6FWbrwHMkFCjNv";

    public static final String WX_SYS_MSG_TYPE_REFERRALREMINDER = "javamedicine";// 复诊提醒
    private static final String WX_SYS_MSG_TIMEOUTSTATUS = "5";// 复诊提醒

    @Autowired
    private RemoterConfig remoterConfig;

    @Autowired
    private PatientFeginClient patientFeginClient;

    @Override
    public boolean sendMsgToWx(Integer msgType, Long fromId, Long toId, String content, Session session) {
        return sendMsgToWx(null, null, msgType, fromId, toId, content, session, false);
    }

    @Override
    public boolean sendMsgToWx(String msgId, String batchId, Integer msgType, Long fromId, Long toId, String content, Session session) {
        return sendMsgToWx(msgId, batchId, msgType, fromId, toId, content, session, false);
    }

    @Override
    public boolean sendMsgToWx(String msgId, String batchId, Integer msgType, Long fromId, Long toId, String content, Session session,
                               boolean ignoreSession) {
        // 构建请求参数
        Long patientId = toId;
        Long doctorId = fromId;
        int ptMsgType;
        Long recomId = null;
        String recomMsg = null;
        String medicalRecordId = null;

        switch (msgType) {
            case Constants.MESSAGE_WEIXIN_SEND_TYPE_TEXT: {
                ptMsgType = PatientMsgSendParamBO.MsgType.TEXT;
                break;
            }
            case Constants.MESSAGE_WEIXIN_SEND_TYPE_IMAGE: {
                ptMsgType = PatientMsgSendParamBO.MsgType.IMAGE;
                break;
            }
            case Constants.MESSAGE_WEIXIN_SEND_TYPE_RADIO: {
                ptMsgType = PatientMsgSendParamBO.MsgType.VOICE;
                break;
            }
            case Constants.MESSAGE_WEIXIN_SEND_TYPE_DRUG: {
                ptMsgType = PatientMsgSendParamBO.MsgType.RECOMMEND;
                RecommandDrug recommandDrug = JSON.parseObject(content, RecommandDrug.class);
                recomId = recommandDrug.getRecommandId();
                recomMsg = recommandDrug.getItems()
                                        .stream()
                                        .map(o -> o.getProductName() + "\n【用法用量：" + o.getUsage() + "】\n")
                                        .collect(Collectors.joining());
                break;
            }
            case Constants.MESSAGE_WEIXIN_DOCTORS_MEDICALRECORD: {
                ptMsgType = PatientMsgSendParamBO.MsgType.MEDICALRECORD;
                DoctorsMedicalRecord doctorsMedicalRecord = JSON.parseObject(content, DoctorsMedicalRecord.class);
                medicalRecordId = doctorsMedicalRecord.getPatientsMedicalRecordId();
                break;
            }
            case Constants.MESSAGE_WEIXIN_SEND_TYPE_PAID_CONSULT: {
                ptMsgType = PatientMsgSendParamBO.MsgType.PAIDCONSULT;
                break;
            }
            default:
                ptMsgType = PatientMsgSendParamBO.MsgType.TEXT;
                break;
        }
        MsgMaPublishParamBO publishParamBO = MsgMaPublishParamBO.builder()
                .doctorId(doctorId)
                .patientId(patientId)
                .content(content)
                .msgId(msgId)
                .msgType(ptMsgType)
                //病历
                .medicalRecordId(medicalRecordId)
                //处方
                .recomId(recomId)
                .build();
        MsgPublishBO msgPublishBO = patientFeginClient.publishMaMessage(publishParamBO);
        LOGGER.info("返回信息：{}", JSONUtil.toJsonStr(msgPublishBO));
//        MsgPublishParamBO publishParamBO = MsgPublishParamBO.builder()
//                                                            .content(content)
//                                                            .doctorId(doctorId)
//                                                            .patientId(patientId)
//                                                            .msgId(msgId)
//                                                            .msgType(ptMsgType)
//                                                            //处方
//                                                            .recomId(recomId)
//                                                            .recomMsg(recomMsg)
//                                                            //病历
//                                                            .medicalRecordId(medicalRecordId)
//                                                            .build();
//        MsgPublishBO msgPublishBO = patientFeginClient.publishMessage(publishParamBO);

        // 如果有返回就是失败了
        if (!msgPublishBO.getSuccess()) {
            LOGGER.error("send message to wx failure, errorCode={}, errorMsg={}", msgPublishBO.getErrorCode(), msgPublishBO.getErrorMsg());
            return false;
        }

        // 发送消息
        LOGGER.info(">>>>>>>>>>>> send message to patient WX , message is {},result {}", publishParamBO.toString(), msgPublishBO.toString());
        return true;
    }

    @Override
    public void pushMsg(Long doctorId, String msg, String userType, String linkUrl) throws BusinessException {

        // 构建请求参数
        Map<String, String> params = new HashMap<>();
        params.put("userId", doctorId + "");
        params.put("userType", userType);
        params.put("pushMessage", msg);
        params.put("linkUrl", linkUrl);

        RestHttpUtil.post().url(remoterConfig.getPushUrl()).paramMap(params).executeData();
    }

    @Override
    public Map<String, String> createSessionBill(SessionDetails session) throws BusinessException {
        // 构建请求参数
        Map<String, String> params = new HashMap<>();
        params.put("sessionId", session.getSessionId());
        params.put("fromId", session.getFromId() + "");
        params.put("toId", session.getToId() + "");
        params.put("inquirerId", session.getInquirerId() + "");
        params.put("beginTime", session.getBeginTime() + "");
        params.put("relation", session.getRelation() + "");
        // params.put("msg", msg);
        // 发送请求
        return RestHttpUtil.post()
                           .url(remoterConfig.getDrAppCreateBillUrl())
                           .paramMap(params)
                           .executeData(new ParameterizedTypeReference<ResponseVO<Map<String, String>>>() {
                           });
    }

    @Override
    public Map<String, String> finishSessionBill(String sessionId, Long endTime, Integer freeFlg, Boolean isManual,
                                                 Boolean isDeletePatient) throws BusinessException {
        // 构建请求参数
        Map<String, String> params = new HashMap<>();
        params.put("sessionId", sessionId);
        params.put("endTime", endTime + "");
        params.put("freeFlag", freeFlg + "");
        params.put("isManual", isManual.toString());
        params.put("isDeletePatient", String.valueOf(isDeletePatient));

        return RestHttpUtil.post()
                           .url(remoterConfig.getDrAppFinishBillUrl())
                           .paramMap(params)
                           .executeData(new ParameterizedTypeReference<ResponseVO<Map<String, String>>>() {
                           });
    }

    @Override
    public void finishSessionDrNotice(Long doctorId, SessionDetails session) {

        // 医生App通知
        Map<String, String> drParams = new HashMap<>();
        drParams.put("userId", doctorId.toString());
        drParams.put("info", JsonMapper.toJson(session));
        RestHttpUtil.post().url(remoterConfig.getFinishSessionDrNoticeUrl()).paramMap(drParams).asyncExecuteData();

    }

    @Override
    public void finishSessionPtNotice(Long patientId, SessionDetails session, Long consultId) throws BusinessException {

        // 患者App通知
        Map<String, String> ptParams = new HashMap<>();

        Map<String, Object> describe = BeanUtil.describe(session);
        describe.put("consultId", consultId);

        ptParams.put("userId", patientId.toString());
        ptParams.put("info", JsonMapper.toJson(describe));

        RestHttpUtil.post().url(remoterConfig.getFinishSessionPtNoticeUrl()).paramMap(ptParams).executeData();
    }

    @Override
    public ConsultPayVO requirePaySession(Long patientId, Long doctorId) throws BusinessException {
        Map<String, String> params = new HashMap<>();
        params.put("patientId", patientId.toString());
        params.put("doctorId", doctorId.toString());
        return RestHttpUtil.post()
                           .url(remoterConfig.getRequirePaySessionUrl())
                           .paramMap(params)
                           .executeData(new ParameterizedTypeReference<ResponseVO<ConsultPayVO>>() {
                           });
    }

    @Override
    public void finishValidSession(String sessionId, Long doctorId, Long patientId, Integer consultSourceType) {
        // 构建请求参数
        Map<String, String> params = new HashMap<>();
        params.put("sessionId", sessionId);
        params.put("doctorId", doctorId + "");
        params.put("patientId", patientId + "");
        params.put("consultSourceType", consultSourceType == null ? String.valueOf(SessionDetails.CONSULT_TYPE_GENERAL) :
                consultSourceType.toString());

        String sign = getFinishValidSessionSign(params, SESSION_NOTICE_SIGN_SECRET_KEY);
        params.put("sign", sign);

        LOGGER.info("remote finishValidSession sessionId:{}, doctorId:{}, patient:{}", sessionId, doctorId, patientId);
        // 发送请求

        String finishValidSessionUrl = remoterConfig.getFinishValidSession();

        /*
         * TODO 此处需要重构,暂时把通知图文咨询和通知患者服务做积分业务在子线程中做同步
         */
        ThreadPoolUtil.execute(() -> {
            if (consultSourceType != null && consultSourceType == SessionDetails.CONSULT_TYPE_CONSULTROOM) {
                /*
                 * 通知图文咨询服务
                 */
                noticeSessionEndToConsult(sessionId, Constants.SESSION_VALID);
            }
            /*
             * 通知患者服务
             */
            try {
                RestHttpUtil.post().url(finishValidSessionUrl).paramMap(params).executeData();
            } catch (BusinessException e) {
                LOGGER.error("结束有效会话通知患者失败", e);
            }
        });

    }

    @Override
    public void finishInvalidSession(String sessionId, Long doctorId, Long patientId, Integer consultSourceType) {
        // 构建请求参数
        Map<String, String> params = new HashMap<>();
        params.put("sessionId", sessionId);
        params.put("doctorId", doctorId + "");
        params.put("patientId", patientId + "");

        String sign = getFinishValidSessionSign(params, SESSION_NOTICE_SIGN_SECRET_KEY);
        params.put("sign", sign);

        LOGGER.info("remote finishInvalidSession sessionId:{}, doctorId:{}, patient:{}", sessionId, doctorId, patientId);
        // 发送请求
        String finishInvalidSessionUrl = remoterConfig.getFinishInvalidSession();

        /*
         * TODO 此处需要重构,暂时把通知图文咨询和通知患者服务做退款业务在子线程中做同步
         */
        ThreadPoolUtil.execute(() -> {
            if (consultSourceType != null && consultSourceType == SessionDetails.CONSULT_TYPE_CONSULTROOM) {
                /*
                 * 通知图文咨询服务
                 */
                noticeSessionEndToConsult(sessionId, Constants.SESSION_INVALID);
            }
            /*
             * 通知患者服务
             */
            try {
                RestHttpUtil.post().url(finishInvalidSessionUrl).paramMap(params).executeData();
            } catch (BusinessException e) {
                LOGGER.error("结束有效会话通知患者失败", e);
            }
        });
    }

    private String getFinishValidSessionSign(Map<String, String> paramMap, String secretKey) {

        String[] paramArr = paramMap.keySet().toArray(new String[]{});
        Arrays.sort(paramArr);

        StringBuilder bd = new StringBuilder();
        for (String param : paramArr) {
            bd.append(param).append("=").append(paramMap.get(param)).append("&");
        }
        bd.append(SESSION_NOTICE_SIGN_KEY).append("=").append(secretKey);
        return MD5.md5(bd.toString());
    }

    @Override
    public boolean checkPtToken(String patientId, String token) throws BusinessException {
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("patientId", patientId);
        paramMap.put("token", token);

        return RestHttpUtil.post()
                           .url(remoterConfig.getCheckPtTokenUrl())
                           .paramMap(paramMap)
                           .executeData(new ParameterizedTypeReference<ResponseVO<Boolean>>() {
                           });
    }

    @Override
    public boolean checkDrToken(String doctorId, String token) throws BusinessException {
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("doctorId", doctorId);
        paramMap.put("token", token);
        return RestHttpUtil.post()
                           .url(remoterConfig.getCheckDrTokenUrl())
                           .paramMap(paramMap)
                           .executeData(new ParameterizedTypeReference<ResponseVO<Boolean>>() {
                           });
    }

    @Override
    public RecomUserInfoDTO getUserInfo(Long doctorId, Long patientId, boolean... fetchNickname) throws Exception {
        Map<String, String> paramMap = new HashMap<>();
        if (doctorId != null) {
            paramMap.put("doctorId", doctorId + "");
        }
        if (patientId != null) {
            paramMap.put("patientId", patientId + "");
        }
        // 默认获取昵称
        boolean fetchBool = true;
        if (fetchNickname.length > 0) {
            fetchBool = fetchNickname[0];
        }
        Integer fetchStatus = fetchBool ? CommonConstant.FETCH_PT_NICKNAME_TRUE : CommonConstant.FETCH_PT_NICKNAME_FALSE;
        // 是否获取昵称
        paramMap.put("fetchNickname", String.valueOf(fetchStatus));
        String url = remoterConfig.getRecomUserInfoUrl();
        return RestHttpUtil.post()
                           .url(url)
                           .paramMap(paramMap)
                           .executeData(new ParameterizedTypeReference<ResponseVO<RecomUserInfoDTO>>() {
                           });
    }

    @Override
    public void noticeSessionEndToConsult(String sessionId, Integer isValid) {
        LOGGER.info("noticeSessionEndToConsult 结束会话通知图文咨询服务,sessionId:{},isValid:{}", sessionId, isValid);
        Map<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("sessionId", sessionId);
        paramMap.put("isEffective", isValid.toString());
        try {
            RestHttpUtil.post().url(remoterConfig.getNoticeSessionEndToConsultUrl()).paramMap(paramMap).executeData();
        } catch (Exception e) {
            LOGGER.error("会话结束通知图文咨询服务发生异常,sessionId:{},isValid:{}", sessionId, isValid);
        }
    }
}
